package com.gitee.wsl.func.filter.bloomfilter.predicate

import com.gitee.wsl.func.predicate.BiPredicate
import com.gitee.wsl.func.predicate.Predicate


/**
 * A predicate that applies the test `func` to each member of the `ary` in
 * sequence for each call to `test()`. if the `ary` is exhausted,
 * the subsequent calls to `test` are executed with a `null` value.
 * If the calls to `test` do not exhaust the `ary` the `processRemaining` method can be called to execute the @{code test} with a
 * `null` value for each remaining `idx` value.
 *
 * @param <T> the type of object being compared.
</T> */
internal class CountingPredicate<T>(
    private val ary: Array<out T>,
    private val func: BiPredicate<T?, T?>
) : Predicate<T> {
    private var idx = 0

    /**
     * Call `BiPredicate<T, T>` for each remaining unpaired `<T>` in the
     * input array. This method should be invoked after the predicate has been
     * passed to a `Extractor.forEach<T>(BiPredicate<T, T>)` to consume any
     * unpaired `<T>`s. The second argument to the BiPredicate will be `null`.
     *
     * @return true if all calls to the predicate were successful
     */
    fun processRemaining(): Boolean {
        // uses local references for optimization benefit.
        var i = idx
        val a = ary
        val limit = a.size
        while (i != limit && func.test(a[i], null)) {
            i++
        }
        return i == limit
    }

    override fun test(t: T): Boolean {
        return func.test(if (idx == ary.size) null else ary[idx++], t)
    }
}
